#include <iostream>
#include <unordered_set>

using std::cout;
using std::endl;
using std::unordered_set;

template <typename Container>
void display(const Container &con)
{
    for(auto &elem : con)
    {
        cout << elem << "  ";
    }
    cout << endl;
}

void test()
{
    //unordered_set的特征
    //1、key值是唯一的，不能重复
    //2、key值是没有顺序的
    //3、底层使用的是哈希
    unordered_set<int> number = {1, 3, 7, 9, 4, 3, 8, 3, 7};
    display(number);
}

class Point
{
public:
    Point(int ix = 0, int iy = 0)
    : _ix(ix)
    , _iy(iy)
    {}

    int getX() const
    {
        return _ix;
    }

    int getY() const
    {
        return _iy;
    }

    ~Point()
    {}

    friend std::ostream &operator<<(std::ostream &os, const Point &rhs);
private:
    int _ix;
    int _iy;
};

std::ostream &operator<<(std::ostream &os, const Point &rhs)
{
    os << "(" << rhs._ix
        << ", " << rhs._iy
        << ")";

    return os;
}

//命令空间是可以进行扩展的
namespace  std
{
//模板的特化
template <>
class hash<Point>
{
public:
    size_t operator()(const Point &rhs) const
    {
        cout << "std::hash" << endl;
        return (rhs.getX() << 1) ^ (rhs.getY() << 2);
    }
};

}//end of namespace std

//自定义哈希函数，函数对象的形式
struct HashPoint
{
    size_t operator()(const Point &rhs) const
    {
        cout << "size_t HashPoint::operator()" << endl;
        return (rhs.getX() << 1) ^ (rhs.getY() << 2);
    }

};

#if 1
//命令空间是可以进行扩展的
namespace  std
{
//模板的特化
template <>
class equal_to<Point>
{
public:
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "std::equal_to" << endl;
        return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY());
    }
};

}//end of namespace std

#endif

bool operator==(const Point &lhs, const Point &rhs)
{
    cout << "bool operator==" << endl;
    return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY());
}

struct EqualToPoint
{
    bool operator()(const Point &lhs, const Point &rhs) const
    {
        cout << "struct EqualToPoint" << endl;
        return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY());
    }

};

void test2()
{
    /* unordered_set<Point> number = { */
    /* unordered_set<Point, HashPoint> number = { */
    unordered_set<Point, HashPoint, EqualToPoint> number = {
        Point(1, 2),
        Point(3, 2),
        Point(1, -2),
        Point(1, 2),
        Point(-1, 2),
        Point(3, 5),
    };
    display(number);
}

int main(int argc, char **argv)
{
    test2();
    return 0;
}

